from pcaimagecompressor import *
from images import *
from webservice_defs import *
from pybrain.structure import FeedForwardNetwork
from pybrain.structure import LinearLayer, SigmoidLayer
from pybrain.structure import FullConnection
from pybrain.supervised.trainers import BackpropTrainer
from pybrain.datasets import ClassificationDataSet

class NNStrategy:

	BLOCK_SIZE = 10
	OUTPUTDIM = 1
	NN_INPUTS = (IMAGE_WIDTH/BLOCK_SIZE) * (IMAGE_HEIGHT/BLOCK_SIZE) * OUTPUTDIM
	NN_OUTPUTS = 1
	DS_TRAIN = 53
	TRAIN_EPOCHS = 200
	LIKE_VALUE = 0.3

	def __init__(self):
		self._nn = self._create_neural_network()
		self._dataset_size = 0
		self._pca_compressor = PCAImageCompressor(IMAGE_WIDTH, IMAGE_HEIGHT, 
												  self.BLOCK_SIZE, 
												  self.OUTPUTDIM)
		self._ds = ClassificationDataSet(self.NN_INPUTS, nb_classes=1, 
										 class_labels=['Like'])
		self._trainer = BackpropTrainer(self._nn, dataset=self._ds, 
										momentum=0.1, verbose=True, 
										weightdecay=0.01)
										
	def recover(self):
		self._nn.sorted = False
		self._nn.sortModules()
		
	def _create_neural_network(self):
		n = FeedForwardNetwork()
		inLayer = LinearLayer(self.NN_INPUTS, name="inLayer")
		hiddenLayer1 = SigmoidLayer(int(0.22*self.NN_INPUTS), name="hidden1")
		hiddenLayer2 = SigmoidLayer(int(0.22*self.NN_INPUTS), name="hidden2")
		outLayer = SigmoidLayer(self.NN_OUTPUTS, name="outLayer")

		n.addInputModule(inLayer)
		n.addModule(hiddenLayer1)
		n.addModule(hiddenLayer2)
		n.addOutputModule(outLayer)

		in_to_first_hidden = FullConnection(inLayer, hiddenLayer1)
		first_hidden_to_second = FullConnection(hiddenLayer1, hiddenLayer2)
		second_hidden_to_out = FullConnection(hiddenLayer2, outLayer)

		n.addConnection(in_to_first_hidden)
		n.addConnection(first_hidden_to_second)
		n.addConnection(second_hidden_to_out)

		n.sortModules()
	
		return n
		
	def compress_image(self, image):
		return self._pca_compressor.compress_image(image)
		
	def train(self, compressed, response):
		response = response/MAX_RESPONSE
		train_input = self._pca_compressor.convert_matrix_to_row(compressed)
		self._ds.appendLinked(train_input, [response])
		self._dataset_size += 1
		if self._dataset_size > 0 and self._dataset_size % self.DS_TRAIN == 0:
			self._nn.reset()
			self._trainer.trainEpochs(self.TRAIN_EPOCHS)

	def is_target_suitable(self, target):
		compressed = target.get_nn_compressed_image()
		if compressed != None:
			test_input = self._pca_compressor.convert_matrix_to_row(compressed)
			r = self._nn.activate(test_input)
			return float(r[0])*MAX_RESPONSE, bool(r[0] >= self.LIKE_VALUE)
		return float(MIN_RESPONSE), False

